/*
 *  MicroEmulator
 *  Copyright (C) 2001 Bartek Teodorczyk <barteo@barteo.net>
 *
 *  It is licensed under the following two licenses as alternatives:
 *    1. GNU Lesser General Public License (the "LGPL") version 2.1 or any newer version
 *    2. Apache License (the "AL") Version 2.0
 *
 *  You may not use this file except in compliance with at least one of
 *  the above two licenses.
 *
 *  You may obtain a copy of the LGPL at
 *      http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
 *
 *  You may obtain a copy of the AL at
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the LGPL or the AL for the specific language governing permissions and
 *  limitations.
 */
 
package org.microemu.device;

import java.util.Vector;

import javax.microedition.lcdui.TextField;


public abstract class InputMethod
{

	public static final int INPUT_NONE = 0;
	public static final int INPUT_123 = 1;
	public static final int INPUT_ABC_UPPER = 2;
	public static final int INPUT_ABC_LOWER = 3;

	/**
     * BlueWhaleSystems fix: Ramesh Nair - 9 May 2008
     * 
     * Allow for devices to not support all available input modes.
     */	
	public static final String[] INPUT_MODE_DESCRIPTION = 
	    { "None", "123", "ABC", "abc" };
	
    private static final int INPUT_MODE_LOWER_BOUND = INPUT_NONE;
    private static final int INPUT_MODE_UPPER_BOUND = INPUT_ABC_LOWER;
	private boolean[] supportedInputModes = new boolean[4];
	
	
	static InputMethod inputMethod = null;
	int inputMode = INPUT_NONE;

	protected InputMethodListener inputMethodListener = null;
	protected int maxSize;


	public InputMethod()
	{
        /**
         * BlueWhaleSystems fix: Ramesh Nair - 9 May 2008
         * 
         * By default all real input modes are unsupported.
         */         
	    clearSupportedInputModes();
	}
	
	// TODO to be removed when event dispatcher will run input method task
	public abstract void dispose();
	
	public abstract int getGameAction(int keyCode);

    public abstract int getKeyCode(int gameAction);

    public abstract String getKeyName(int keyCode) throws IllegalArgumentException;


	public void removeInputMethodListener(InputMethodListener l)
	{
		if (l == inputMethodListener) {
			inputMethodListener = null;
			setInputMode(INPUT_NONE);
		}
	}


	public void setInputMethodListener(InputMethodListener l)
	{
        /**
         * BlueWhaleSystems fix: Ramesh Nair - 9 May 2008
         *
         * Only use supported input modes.
         */     
	    
		inputMethodListener = l;
        switch (l.getConstraints() & TextField.CONSTRAINT_MASK) {
	        case TextField.ANY :
	        case TextField.EMAILADDR :
	        case TextField.URL :
                if (isInputModeSupported( INPUT_ABC_LOWER ))
                {
                    setInputMode(INPUT_ABC_LOWER);
                }
                else if (isInputModeSupported( INPUT_ABC_UPPER ))
                {
                    setInputMode(INPUT_ABC_UPPER);
                }
                else
                {
                    setInputMode(INPUT_NONE);
                    
                }
	            break;
	        case TextField.NUMERIC :
	        case TextField.PHONENUMBER :
	        case TextField.DECIMAL :
	            if (isInputModeSupported( INPUT_123 ))
	            {
	                setInputMode(INPUT_123);
	            }
	            else
	            {
	                setInputMode( INPUT_NONE );
	            }
	            break;
	    }
	}
  
  
	public int getInputMode()
	{
		return inputMode;
	}


	public void setInputMode(int mode)
	{
		/**
		 * Set the input mode to the next available one.
		 * 
		 * BlueWhaleSystems fix: Ramesh Nair - 9 May 2008
		 */
       if (INPUT_MODE_LOWER_BOUND <= mode && INPUT_MODE_UPPER_BOUND >= mode)
       {
           inputMode = mode;
       }
	}

	/**
	 * Set the input mode to the next available one.
	 * 
	 * BlueWhaleSystems fix: Ramesh Nair - 9 May 2008
	 */
    public void setToNextRealInputMode()
    {
       int newInputMode = inputMode;
       
       // stop if no other supported modes are available
       // (by default 'None' is a supported input mode)
       while (++newInputMode != inputMode)
       {
           // only if it's a real, supported mode
           if (INPUT_NONE != newInputMode && isInputModeSupported( newInputMode ))
           {
               setInputMode( newInputMode );
               return;
           }
           // wrap around
           if (INPUT_MODE_UPPER_BOUND <= newInputMode)
           {
               newInputMode = INPUT_MODE_LOWER_BOUND - 1;
           }           
       }
    }	
	
	
	
    /**
     * Set the given input mode to be supported.
     * 
     * BlueWhaleSystems fix: Ramesh Nair - 9 May 2008
     */ 
	public void setInputModeIsSupported(int aMode)
	{
	    if (INPUT_MODE_LOWER_BOUND <= aMode && INPUT_MODE_UPPER_BOUND >= aMode)
	    {
	        supportedInputModes[aMode] = true;
	    }
	}
	
	
	
    /**
     * Clear "supported" flag for all input modes, i.e. no modes should be 
     * supported.
     * 
     * BlueWhaleSystems fix: Ramesh Nair - 9 May 2008
     */ 
    public void clearSupportedInputModes()
    {
        for (int i=INPUT_MODE_LOWER_BOUND; i<=INPUT_MODE_UPPER_BOUND; ++i)
        {
            supportedInputModes[i] = false;
        }
        supportedInputModes[INPUT_NONE] = true;    // always supported
    }	
	
	
	
    /**
     * Get whether the given input mode is supported.
     * 
     * BlueWhaleSystems fix: Ramesh Nair - 9 May 2008
     */ 
	public boolean isInputModeSupported(int aMode)
	{
        if (INPUT_MODE_LOWER_BOUND <= aMode && INPUT_MODE_UPPER_BOUND >= aMode)
        {
            return supportedInputModes[aMode];
        }
        return false;
	}
	
	

    public void setMaxSize(int maxSize)
	{
		this.maxSize = maxSize;
	}
    
    public static boolean validate(String text, int constraints) 
    {
        switch (constraints & TextField.CONSTRAINT_MASK) {
            case TextField.ANY :
                break;
            case TextField.EMAILADDR :
                // TODO validate email
                break;
            case TextField.NUMERIC :
                if (text != null && text.length() > 0 && !text.equals("-")) {
                    try { 
                        Integer.parseInt(text); 
                    } catch (NumberFormatException e) { 
                        return false;
                    }
                }
                break;
            case TextField.PHONENUMBER :
                // TODO validate email
                break;
            case TextField.URL :
                // TODO validate url
                break;
            case TextField.DECIMAL :
                if (text != null && text.length() > 0 && !text.equals("-")) {
                    try {
                        Double.valueOf(text);
                    } catch (NumberFormatException e) { 
                        return false;
                    }
                }
                break;
        }
        
        return true;
    }

}
